package extension.game.poker.handeval;

/**
 * Lớp kết quả
 * @author HaiNH
 *
 */
public class TexasHoldemHandResult {

    /**
     * Loại của bộ bài được đánh giá (High card, Pair, Two Pair, ...)
     */
    public final int type;
    /**
     * Xếp hạng. Hạng càng lớn thì bộ bài càng có giá trị.
     */
    public final int rank;
    /**
     * chỉ số index của các quân bài tạo ra bộ 5 mạnh nhất. Giá trị các phần tử
     * nằm trong khoảng từ <code>0 -> hand.length - 1</code>
     */
    public final int[] highest5Card = new int[5];
    /**
     * Bộ các quân bài đang đc đánh giá.
     */
    private int[] hand;
    public final int numOfSignificantCards;

    /**
     * Tạo kết quả
     * @param hand mảng chứa từ 5 -> 7 quân bài theo dạng index từ 0 -> 51
     */
    public TexasHoldemHandResult(int[] hand) {
        CardSet cards = CardConverter.toCardSet(hand);
        if (hand.length == 5) {
            rank = HandEval.hand5Eval(HandEval.encode(cards));
        } else if (hand.length == 6) {
            rank = HandEval.hand6Eval(HandEval.encode(cards));
        } else if (hand.length == 7) {
            rank = HandEval.hand7Eval(HandEval.encode(cards));
        } else {
            throw new IllegalArgumentException("Length of hand is not valid: "
                    + hand.length);
        }
        this.hand = hand;
        type = (rank & 0x0F000000) >> 24;
        int[] evaluatedCards = new int[5];
        for (int i = 0; i < 5; i++) {
            evaluatedCards[i] = (rank & (0x0f << ((4 - i) * 4))) >> ((4 - i) * 4);
        }

        switch (type) {
            case 0: // High-card
            case 5: // Flush
                for (int i = 0; i < 5; i++) {
                    highest5Card[i] = cards.search(evaluatedCards[i])[0];
                }
                numOfSignificantCards = 5;
                break;
            case 1: // Pair
                int[] pair = cards.search(evaluatedCards[0]);
                highest5Card[0] = pair[0];
                highest5Card[1] = pair[1];
                for (int i = 1; i < 4; i++) {
                    highest5Card[i + 1] = cards.search(evaluatedCards[i])[0];
                }
                numOfSignificantCards = 2;
                break;
            case 2: // Two-Pair
                int[] pair0 = cards.search(evaluatedCards[0]);
                highest5Card[0] = pair0[0];
                highest5Card[1] = pair0[1];
                pair0 = cards.search(evaluatedCards[1]);
                highest5Card[2] = pair0[0];
                highest5Card[3] = pair0[1];
                highest5Card[4] = cards.search(evaluatedCards[2])[0];
                numOfSignificantCards = 4;
                break;
            case 3: // Three-of-a-kind
                int[] triple = cards.search(evaluatedCards[0]);
                for (int i = 0; i < 3; i++) {
                    highest5Card[i] = triple[i];
                }
                highest5Card[3] = cards.search(evaluatedCards[1])[0];
                highest5Card[4] = cards.search(evaluatedCards[2])[0];
                numOfSignificantCards = 3;
                break;
            case 4: // Straight
            case 8: // STRAIGHT_FLUSH
                for (int i = 0; i < 5; i++) {
                    highest5Card[i] = cards.search((evaluatedCards[0] - i + 13) % 13)[0];
                }
                numOfSignificantCards = 5;
                break;
            case 6: // Full-house
                int[] triple0 = cards.search(evaluatedCards[0]);
                for (int i = 0; i < 3; i++) {
                    highest5Card[i] = triple0[i];
                }
                int[] pair1 = cards.search(evaluatedCards[1]);
                highest5Card[3] = pair1[0];
                highest5Card[4] = pair1[1];
                numOfSignificantCards = 5;
                break;
            case 7: // FOUR_OF_A_KIND
                int[] quad = cards.search(evaluatedCards[0]);
                for (int i = 0; i < 4; i++) {
                    highest5Card[i] = quad[i];
                }
                highest5Card[4] = cards.search(evaluatedCards[1])[0];
                numOfSignificantCards = 4;
                break;
            default:
                numOfSignificantCards = 0;
        }
    }

    @Override
    public String toString() {
        int[] hand = new int[5];
        for (int i = 0; i < 5; i++) {
            hand[i] = this.hand[highest5Card[i]];
        }
        return "Type:\t\t" + Ranks[type]
                + "\nRank: \t\t" + rank
                + "\nPositions:\t" + toString(highest5Card)
                + "\nSignificant cards: " + numOfSignificantCards
                + "\nCards: \t\t" + CardConverter.toCardSet(hand).toString()
                + "\nOrigin 7 cards: " + CardConverter.toCardSet(this.hand).toString();
    }

    public static String toString(int[] array) {
        StringBuilder res = new StringBuilder("[");
        for (int i = 0; i < array.length; i++) {
            res.append(array[i]).append(", ");
        }
        res.delete(res.length() - 2, res.length()).append(']');
        return res.toString();
    }
    public static String[] Ranks = new String[]{"NO_PAIR", "PAIR",
        "TWO_PAIR", "THREE_OF_A_KIND", "STRAIGHT", "FLUSH", "FULL_HOUSE",
        "FOUR_OF_A_KIND", "STRAIGHT_FLUSH"};
}
